package cn.edu.tju.elm.model.entity;

import cn.edu.tju.core.model.BaseEntity;
import cn.edu.tju.core.model.User;
import cn.edu.tju.elm.exception.MethodArgumentNotValidException;
import jakarta.persistence.*;
import lombok.*;
import lombok.experimental.SuperBuilder;
import org.hibernate.annotations.DynamicUpdate;
import org.hibernate.annotations.Where;

import java.math.BigDecimal;
import java.time.LocalDateTime;

@Entity
@Table(name = "virtual_wallet")
@Data
@SuperBuilder
@AllArgsConstructor
@NoArgsConstructor
@Where(clause = "is_deleted=false")
@DynamicUpdate
public class VirtualWallet extends BaseEntity {

    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id", nullable = false, unique = true)
    private User user;

    @Column(precision = 15, scale = 2, nullable = false, columnDefinition = "DECIMAL(15,2) DEFAULT 0.00")
    private BigDecimal balance; // 可用余额

    @Column(precision = 15, scale = 2, nullable = false, columnDefinition = "DECIMAL(15,2) DEFAULT 0.00")
    private BigDecimal frozenBalance; // 冻结余额

    @Column(precision = 15, scale = 2, nullable = false, columnDefinition = "DECIMAL(15,2) DEFAULT 0.00")
    private BigDecimal overdraftLimit; // 透支额度

    @Column(name = "is_vip", nullable = false, columnDefinition = "TINYINT(1) DEFAULT 0")
    private Boolean isVip = false; // 新增VIP标识

    @Column(name = "vip_since")
    private LocalDateTime vipSince; // 成为VIP的时间

    // ========== 充血模型业务方法 ==========

    /**
     * 充值
     */
    public void recharge(User updater,BigDecimal amount, RewardRule rule) {
        if (amount.compareTo(BigDecimal.ZERO) <= 0) {
            throw new MethodArgumentNotValidException("充值金额必须大于0");
        }
        BigDecimal actualAmount = calculateRechargeAmount(amount, rule);
        this.balance = this.balance.add(actualAmount);
        this.updater = updater.getId();
        this.updateTime = LocalDateTime.now();
    }

    /**
     * 提现
     */
    public void withdraw(User updater, BigDecimal amount, RewardRule rule) {
        if (amount.compareTo(BigDecimal.ZERO) <= 0) {
            throw new MethodArgumentNotValidException("提现金额必须大于0");
        }
        if (!canWithdraw(amount)) {
            throw new MethodArgumentNotValidException("余额不足");
        }
        BigDecimal actualAmount = calculateWithdrawAmount(amount, rule);
        this.balance = this.balance.subtract(actualAmount);
        this.updateTime = LocalDateTime.now();
        this.updater = updater.getId();
    }

    /**
     * 支付（转账给另一个钱包）
     */
    public void transferTo(VirtualWallet targetWallet, BigDecimal amount) {
        if (amount.compareTo(BigDecimal.ZERO) <= 0) {
            throw new MethodArgumentNotValidException("转账金额必须大于0");
        }
        if (!canWithdraw(amount)) {
            throw new MethodArgumentNotValidException("余额不足");
        }
        this.balance = this.balance.subtract(amount);
        targetWallet.balance = targetWallet.balance.add(amount);
    }

    /**
     * 冻结资金
     */
    public void freeze(BigDecimal amount) {
        if (amount.compareTo(BigDecimal.ZERO) <= 0) {
            throw new MethodArgumentNotValidException("冻结金额必须大于0");
        }
        if (this.balance.compareTo(amount) < 0) {
            throw new MethodArgumentNotValidException("余额不足，无法冻结");
        }
        this.balance = this.balance.subtract(amount);
        this.frozenBalance = this.frozenBalance.add(amount);
    }

    /**
     * 解冻资金
     */
    public void unfreeze(BigDecimal amount) {
        if (amount.compareTo(BigDecimal.ZERO) <= 0) {
            throw new MethodArgumentNotValidException("解冻金额必须大于0");
        }
        if (this.frozenBalance.compareTo(amount) < 0) {
            throw new MethodArgumentNotValidException("冻结金额不足");
        }
        this.frozenBalance = this.frozenBalance.subtract(amount);
        this.balance = this.balance.add(amount);
    }

    /**
     * 检查是否可以提现/支付（考虑透支额度）
     */
    public boolean canWithdraw(BigDecimal amount) {
        return this.balance.add(this.overdraftLimit).compareTo(amount) >= 0;
    }

    /**
     * 获取总余额（可用 + 冻结）
     */
    public BigDecimal getTotalBalance() {
        return this.balance.add(this.frozenBalance);
    }

    /**
     * 升级为VIP用户
     */
    public void upgradeToVip(BigDecimal defaultOverdraftLimit) {
        this.isVip = true;
        this.vipSince = LocalDateTime.now();
        this.overdraftLimit = defaultOverdraftLimit;
    }

    /**
     * 检查是否为VIP用户
     */
    public boolean isVipUser() {
        return Boolean.TRUE.equals(this.isVip);
    }

    // ========== 私有计算方法 ==========

    private BigDecimal calculateRechargeAmount(BigDecimal amount, RewardRule rule) {
        if (rule == null || !rule.getIsActive()) {
            return amount;
        }
        return amount.add(rule.calculateReward(amount));
    }

    private BigDecimal calculateWithdrawAmount(BigDecimal amount, RewardRule rule) {
        if (rule == null || !rule.getIsActive()) {
            return amount;
        }
        return amount.add(rule.calculateFee(amount));
    }
}